package com.googlecode.perfectable.persistable.storage;

import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;

import com.googlecode.perfectable.persistable.session.Identifier;
import com.googlecode.perfectable.persistable.session.IdentifierGenerator;
import com.googlecode.perfectable.persistable.session.InvalidReference;
import com.googlecode.perfectable.persistable.session.Sequence;

public abstract class AbstractStorage implements Storage {
	private final IdentifierGenerator generator = new Sequence();
	private final Set<Object> currentlyPersisting = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>());

	@Override
	public abstract <T> T materialize(Identifier<T> identity) throws InvalidReference;

	protected abstract <T> void doPersist(T entity, Identifier<? super T> identity);

	@Override
	public final <T> void persist(T entity, Identifier<? super T> identity) {
		if(this.currentlyPersisting.contains(entity)) {
			return;
		}
		this.currentlyPersisting.add(entity);
		try {
			doPersist(entity, identity);
		}
		finally {
			this.currentlyPersisting.remove(entity);
		}
	}

	@Override
	public final synchronized <T> Identifier<T> persist(T entity) {
		Identifier<T> identity = this.generator.generate();
		persist(entity, identity);
		return identity;
	}

}
